/*
 * CompressionDeflate
 *
 * Copyright (c) 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
 * All rights reserved.
 * 
 * C# translation Adam Sida
 */
using System;
//using Petra.Gis.Imaging.Tiff.Deflated;
//using System.IO.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression;
using System.Collections.Generic;
//using System.Drawing;
//using System.Drawing.Imaging;
using System.Windows;


namespace Petra.Gis.ImagingServices.Tiff
{
/**
 * A TIFF decoder for files compressed with the <em>Deflated</em> method.
 * This compression algorithm has the values <code>31946</code> 
 * ({@link TIFFConstants#COMPRESSION_DEFLATED_INOFFICIAL}) and <code>8</code>
 * ({@link TIFFConstants#COMPRESSION_DEFLATED_OFFICIAL}) 
 * in the compression tag of an image file directory.
 * All types of image data can be compressed with this method.
 * <p>
 * This decoder makes use of the package java.util.zip which comes with an Inflater
 * class that does most of the work.
 * All the decoder has to do is feed the Inflater object with compressed data from
 * the input file and give decompressed data received from the Inflater to the
 * putBytes method.
 * @author Marco Schmidt
 * @since 0.9.0
 */
  public class CompressionDeflate : Compression
  {

    Inflater _inflater;
    //DeflateStream _inflater;



    public CompressionDeflate()
      : base()
    {
      _inflater = new Inflater();
    }



    //public CompressionDeflate(TiffBitmapPage currImage)
    //  : base(currImage)
    //{

    //  _inflater = new Inflater();
    //}



    //public static override Compression CreateCompressionInstance(TiffBitmapPage currImage)
    //{
    //  return new CompressionDeflate(currImage);

    //}


    public override byte[] DecompressBlock(BitmapBlock block, byte[] comprData, int srcBitsPerSample)
    {

      if (_inflater == null)
        _inflater = new Inflater();

      //if (_image == null)
      //  throw new InvalidOperationException("no image presents to decompress");

      if (srcBitsPerSample % 8 != 0)
        throw new UnsupportedTypeException("sorry unsupported, bits per sample must be modulo of 8");

      // decompress always using padding dimensions !
      int outDataLen = block.PaddingWidth * block.PaddingHeight * (srcBitsPerSample / 8);

      if (_uncompressedDataBuff == null)
        _uncompressedDataBuff = new byte[outDataLen];
      else if (_uncompressedDataBuff.Length != outDataLen)
        Array.Resize<byte>(ref _uncompressedDataBuff, outDataLen);

      //inflate directly into bitmap needed ??
      //byte[] outData = new byte[outDataLength];

      _inflater.Reset();
      try
      {
        _inflater.SetInput(comprData);
        _inflater.Inflate(_uncompressedDataBuff);
      }
      catch { }

      return alignDataToStride(block.PaddingWidth, block.PaddingHeight, _uncompressedDataBuff, srcBitsPerSample);

      //if (BitmapBlock.GetStrideLenght(block.Bounds.Width, srcBitsPerSample) != (block.Bounds.Width * (srcBitsPerSample / 8) ))
      //  return alignDataToStride(block.PaddingWidth, block.PaddingHeight, _uncompressedDataBuff, srcBitsPerSample);
      //else
      //  return _uncompressedDataBuff;
    
    }




    //public override void decode()
    //{

    //  byte[] inputData;  //disk data buffer

    //  //todo: change this all by image type !!!
    //  _blockPixelFormat = PixelFormat.Format8bppIndexed;
    //  _outPixelFormat = _blockPixelFormat;
    //  _bitsPerPixel = 8;
    //  //end

    //  int bandDataBytesLength;
    //  int outDataLength;
    //  int rowLength; //defines lenght of row in bytes
    //  int rowCounter; //counts number of bytes per row
    //  int dataCouter;

    //  byte[] outData;

    //  //create new bitmap
    //  Bitmap bmp = new Bitmap(_image.PixelWidth, _image.PixelHeight, _outPixelFormat); //just for now

    //  foreach (KeyValuePair<BandType, Band> bdnKey in _image.Bands)
    //  {
    //    //compute skip bytes for current band, if interleaved
    //    int skipOtherBandBytesLenght = _bitsPerPixel - bdnKey.Value.BitsPerBand;
    //    if ((skipOtherBandBytesLenght % 8) != 0 || (bdnKey.Value.BitsPerBand % 8) != 0)
    //      throw new ArgumentException("unsupported bit depth in image or in band, both must be modulo of 8");

    //    bandDataBytesLength = bdnKey.Value.BitsPerBand >> 3; // = / 8

    //    foreach (Block b in bdnKey.Value.Blocks)
    //    {
    //      //read compressed data from tiff file
    //      _tiffReader.BaseStream.Seek(b.Offset, System.IO.SeekOrigin.Begin);
    //      inputData = _tiffReader.ReadBytes(b.CompressedSize);

    //      //handle different block dimensions in tiled images
    //      //LockBits by tile size
    //      BitmapData bd = bmp.LockBits(new Rectangle(b.BlockX1, b.BlockY1, b.Width, b.Height), ImageLockMode.ReadWrite, _outPixelFormat);

    //      //get bitmap start pointer
    //      byte* browPtr = (byte*)bd.Scan0;

    //      //for interleaved images
    //      //start to fill image with data from current band first position
    //      browPtr += (int)bdnKey.Key;

    //      outDataLength = b.Height * b.Width * bandDataBytesLength;

    //      //inflate directly into bitmap needed !!!
    //      outData = new byte[outDataLength];
    //      _inflater.Reset();
    //      _inflater.SetInput(inputData);
    //      _inflater.Inflate(outData);

    //      dataCouter = 0;
    //      rowLength = (b.Width * bandDataBytesLength);
    //      rowCounter = 0;

    //      while (dataCouter < outDataLength)
    //      {
    //        if (rowCounter++ == rowLength)
    //        {
    //          browPtr += bd.Stride - rowLength; 
    //          rowCounter = 1; 
    //        }
    //        *browPtr++ = outData[dataCouter++];
    //      }


    //      //_inflater.reset();
    //      //_inflater.Inflate(inputData, browPtr, outDataLength, bandDataBytesLength, skipOtherBandBytesLenght);

    //      bmp.UnlockBits(bd);

    //    }
    //  }

    //  bmp.Save("e:\\rastry\\test1.bmp", ImageFormat.Bmp);


    //}


    //private DataInput din;
    //private int compressedSize;

    //public void decode_old()
    //{
    //  Inflater inflater = new Inflater();
    //  byte[] ioBuffer = new byte[20000];
    //  byte[] data = new byte[getBytesPerRow()];
    //  // determine how many bytes have to be read from inflater
    //  int numRows = getY2();
    //  //TIFFImageFileDirectory ifd = this.Ifd;
    //  if (numRows > _image.Height - 1)
    //  {
    //    numRows = _image.Height - 1;
    //  }
    //  numRows -= getY1();
    //  int remainingBytes = numRows * data.Length;
    //  // now read and decompress as long as there is data left to decompress
    //  while (compressedSize > 0 || remainingBytes > 0)
    //  {
    //    if (inflater.needsInput())
    //    {
    //      // read compressed data from input
    //      int numBytes;
    //      if (compressedSize > ioBuffer.Length)
    //      {
    //        numBytes = ioBuffer.Length;
    //      }
    //      else
    //      {
    //        numBytes = compressedSize;
    //      }
    //      ioBuffer = _tiffReader.ReadBytes(numBytes);
    //      // give data to inflater
    //      inflater.setInput(ioBuffer, 0, numBytes);
    //      compressedSize -= numBytes;
    //    }
    //    else
    //    {
    //      // determine how many bytes to decompress in this loop iteration
    //      int numBytes;
    //      if (remainingBytes > data.Length)
    //      {
    //        numBytes = data.Length;
    //      }
    //      else
    //      {
    //        numBytes = remainingBytes;
    //      }
    //      int numInflated;
    //      // do the decompression
    //      try
    //      {
    //        numInflated = inflater.inflate(data, 0, numBytes);
    //      }
    //      catch
    //      {
    //        throw new InvalidFileStructureException("Error in compressed input data: ");
    //      }
    //      // store decompressed data and update number of bytes left to decompress
    //      if (numInflated > 0)
    //      {
    //        putBytes(data, 0, numInflated);
    //        remainingBytes -= numInflated;
    //      }
    //    }
    //  }
    //}

    public override CompressionType[] CompressionTypes
    {
      get { return new CompressionType[] { CompressionType.DEFLATE_INOFFICIAL, CompressionType.DEFLATE }; }
    }

    //public void initialize()
    //  //throws IOException, MissingParameterException
    //{
    //  base.initialize();
    //  din = getInput();
    //  compressedSize = this.ImageFileDirectory.getByteCount(getTileIndex());
    //}	
  }
}